package presentation.rest;

import com.sun.jersey.spi.resource.Singleton;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import presentation.twitter.Comment;
import presentation.twitter.Tweet;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Singleton
@Path("tweets/object")
public class TweetObjectResource {

	private final static Logger logger = LoggerFactory.getLogger(TweetObjectResource.class);

	@GET
	@Path("{username: [a-zA-Z][a-zA-Z_0-9]*}/stream")
	@Produces({MediaType.APPLICATION_JSON, ServiceLocator.MEDIA_TYPE_X_JAVASCRIPT})
	public Response stream(
			@Context HttpHeaders headers,
			@PathParam("username") String username,
			@QueryParam("callback") @DefaultValue("stream") String callback
	) {

		final List<Tweet> tweets = ServiceLocator.TWITTER.findStream(username);
		logger.info("Found stream username = {}.", username);

		ArrayNode entity = buildJson(tweets);

		return ResponseBuilder.newBuilder()
				.setHeaders(headers)
				.setCallback(callback)
				.setEntity(entity)
				.build();
	}

	@GET
	@Path("{username: [a-zA-Z][a-zA-Z_0-9]*}")
	@Produces({MediaType.APPLICATION_JSON, ServiceLocator.MEDIA_TYPE_X_JAVASCRIPT})
	public Response tweets(
			@Context HttpHeaders headers,
			@PathParam("username") String username,
			@QueryParam("callback") @DefaultValue("stream") String callback
	) {
		final List<Tweet> tweets = ServiceLocator.TWITTER.findTweets(username);
		logger.info("Found tweets username = {}.", username);

		ArrayNode entity = buildJson(tweets);

		return ResponseBuilder.newBuilder()
				.setHeaders(headers)
				.setCallback(callback)
				.setEntity(entity)
				.build();
	}

	private ArrayNode buildJson(List<Tweet> tweets) {
		ArrayNode entity = ServiceLocator.OBJECT_MAPPER.createArrayNode();
		for (Tweet tweet : tweets) {
			ObjectNode tweetOn = entity.addObject();
			tweetOn.put("tweetId", tweet.getTweetId());
			tweetOn.put("username", tweet.getUsername());
			tweetOn.put("message", tweet.getMessage());
			tweetOn.put("date", tweet.getDate().getTime());

			ArrayNode c = tweetOn.putArray("comments");
			for (Comment comment : tweet.getComments()) {
				ObjectNode commentOn = c.addObject();
				commentOn.put("username", comment.getUsername());
				commentOn.put("comment", comment.getComment());
				commentOn.put("date", comment.getDate().getTime());
			}
		}
		return entity;
	}

	@POST
	@Consumes(MediaType.APPLICATION_JSON)
	public Response create(ObjectNode tweet) {

		Tweet.Builder tweetBuilder = Tweet.newBuilder();
		tweetBuilder.setUsername(tweet.get("username").asText());
		tweetBuilder.setMessage(tweet.get("message").asText());
		tweetBuilder.setDate(new Date(tweet.get("date").asLong()));

		ServiceLocator.TWITTER.addTweet(tweetBuilder);
		logger.info("Created tweet = {}.", tweetBuilder);
		return Response.ok().build();
	}

	@PUT
	@Path("{tweetId}")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response update(@PathParam("tweetId") long tweetId, ObjectNode comment) {

		Comment.Builder commentBuilder = Comment.newBuilder();
		commentBuilder.setTweetId(tweetId);
		commentBuilder.setUsername(comment.get("username").asText());
		commentBuilder.setComment(comment.get("comment").asText());
		commentBuilder.setDate(new Date(comment.get("date").asLong()));

		ServiceLocator.TWITTER.addComment(commentBuilder.withTweetId(tweetId).build());
		logger.info("Created tweet with comment = {}", commentBuilder);
		return Response.ok().build();
	}

	@DELETE
	@Path("{username: [a-zA-Z][a-zA-Z_0-9]*}")
	public Response remove(@PathParam("username") String username) {
		ServiceLocator.TWITTER.removeUsername(username);
		logger.info("Removed username = {}.", username);
		return Response.ok(Response.Status.OK).build();
	}

	@POST
	@Path("{username: [a-zA-Z][a-zA-Z_0-9]*}/follow")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response follow(@PathParam("username") String username, ObjectNode on) {

		final List<String> usernames = new ArrayList<String>();
		for (JsonNode n : on) {
			usernames.add(n.asText());
		}

		ServiceLocator.TWITTER.follow(username, usernames);
		logger.info("Username = {} will follow:  {}.", username, usernames);
		return Response.ok().build();
	}
}
